import { createContext, ReactNode, useEffect, useRef, useState } from 'react'
import { Node } from 'reactflow'
import { APIKindType } from '../types/api'
import { typesContextType } from '../types/typesContext'

// context to share types adn functions from nodes to flow
// 技能组件模板

const initialValue: typesContextType = {
  reactFlowInstance: null,
  setReactFlowInstance: () => {},
  deleteNode: () => {},
  types: {},
  setTypes: () => {},
  templates: {},
  setTemplates: () => {},
  data: {},
  setData: () => {},
  loadAllData: () => {}
}

export const typesContext = createContext<typesContextType>(initialValue)

export function TypesProvider({ children }: { children: ReactNode }) {
  const [types, setTypes] = useState({})
  const [reactFlowInstance, setReactFlowInstance] = useState(null)
  const [templates, setTemplates] = useState({})
  const [data, setData] = useState({})

  // 用来控制只调用一次 /all接口
  const isLoaded = useRef(false)

  useEffect(() => {
    const result = []
    updateTypes(result)
  }, [])

  function deleteNode(idx: string) {
    if (!reactFlowInstance) return
    reactFlowInstance.setNodes(reactFlowInstance.getNodes().filter((n: Node) => n.id !== idx))
    reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter(ns => ns.source !== idx && ns.target !== idx))
  }

  function updateTypes(result) {
    setData(result)
    setTemplates(
      Object.keys(result).reduce((acc, curr) => {
        Object.keys(result[curr]).forEach((c: keyof APIKindType) => {
          acc[c] = result[curr][c]
        })
        return acc
      }, {})
    )
    // Set the types by reducing over the keys of the result data and updating the accumulator.
    setTypes(
      // Reverse the keys so the tool world does not overlap
      Object.keys(result)
        .reverse()
        .reduce((acc, curr) => {
          Object.keys(result[curr]).forEach((c: keyof APIKindType) => {
            acc[c] = curr
            // Add the base classes to the accumulator as well.
            result[curr][c].base_classes?.forEach(b => {
              acc[b] = curr
            })
          })
          return acc
        }, {})
    )
  }

  function loadAllData() {
    // if (!isLoaded.current) {
    //   getAll().then(res => {
    //     updateTypes(res)
    //   })
    //   isLoaded.current = true
    // }
    isLoaded.current = true
  }

  return (
    <typesContext.Provider
      value={{
        types,
        setTypes,
        reactFlowInstance,
        setReactFlowInstance,
        deleteNode,
        setTemplates,
        templates,
        data,
        setData,
        loadAllData
      }}
    >
      {children}
    </typesContext.Provider>
  )
}
